package com.xinchuang.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.xinchuang.comment.R;
import com.xinchuang.common.KeyWordSystem;
import com.xinchuang.common.Result;
import com.xinchuang.common.ResultUtil;
import com.xinchuang.constant.ImageTypeConstant;
import com.xinchuang.entity.common.FileTable;
import com.xinchuang.entity.image.*;
import com.xinchuang.entity.repacigi.RepacigiBaseTable;
import com.xinchuang.entity.repacigi.RepacigiMainTable;
import com.xinchuang.entity.repacigi.RepacigiSubTable;
import com.xinchuang.entity.targetSystem.system.TargetSubType;
import com.xinchuang.entity.targetSystem.system.TargetType;
import com.xinchuang.mapper.image.TaskRunMapper;
import com.xinchuang.mapper.repacigi.RepacigiBaseTableMapper;
import com.xinchuang.mapper.repacigi.RepacigiMainTableMapper;
import com.xinchuang.mapper.repacigi.RepacigiSubTableMapper;
import com.xinchuang.mapper.targetSystem.TargetTypeMapper;
import com.xinchuang.service.RedisUseService;
import com.xinchuang.service.ReorganizeService;
import com.xinchuang.service.TiffUtilService;
import com.xinchuang.service.common.FileTableService;
import com.xinchuang.service.common.ImgTargetTableService;
import com.xinchuang.service.image.*;
import com.xinchuang.service.repacigi.RepacigiBaseTableService;
import com.xinchuang.service.repacigi.RepacigiMainTableService;
import com.xinchuang.service.repacigi.RepacigiSubTableService;
import com.xinchuang.service.targetSystem.TargetSubTypeService;
import com.xinchuang.socket.WebSocketServer;
import com.xinchuang.util.FileElseUtil;
import com.xinchuang.util.LngLatUtil;
import com.xinchuang.util.RedisUtil;
import com.xinchuang.utils.CommonUtil;
import com.xinchuang.utils.DateUtils;
import com.xinchuang.utils.MyUtil;
import com.xinchuang.utils.WordUtils;
import com.xinchuang.vo.*;
import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.images.FileImageProvider;
import fr.opensagres.xdocreport.document.images.IImageProvider;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ReorganizeServiceImpl implements ReorganizeService {

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private SnowflakeGenerator snow = new SnowflakeGenerator(1, 1);

    // 定义日期时间格式
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Resource
    private RepacigiBaseTableMapper repacigiBaseTableMapper;
    @Resource
    private RepacigiMainTableMapper repacigiMainTableMapper;
    @Resource
    private RepacigiSubTableMapper repacigiSubTableMapper;

    @Resource
    private ImgTargetTableService imgTargetTableService;

    @Resource
    private ImageResultService imageResultService;

    @Resource
    private ImageEditingService imageEditingService;

    @Resource
    private ImageSpecialSubjectService imageSpecialSubjectService;

    @Resource
    private RepacigiBaseTableService repacigiBaseTableService;

    @Resource
    private RepacigiMainTableService repacigiMainTableService;

    @Resource
    private RepacigiSubTableService repacigiSubTableService;

    @Resource
    private FileTableService fileTableService;

    @Resource
    private GDALService gdalService;

    @Value("${mbRecognitionSubsystem.fileUploadDir}")
    private String fileUploadDir;

    @Resource
    private ImageCutService imageCutService;

    @Resource
    private TargetTypeMapper targetTypeMapper;

    @Resource
    private TargetSubTypeService targetSubTypeService;

    @Resource
    private KeyWordSystem keyWordSystem;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private WebSocketServer webSocketServer;

    @Resource
    private RedisUseService redisUseService;

    @Resource
    private TiffUtilService tiffUtilService;

    @Resource
    private RecognitionTableService recognitionTableService;

    @Resource
    private TaskRunMapper taskRunMapper;

    @Override
    public String autoCorrect(JSONObject jsonObject) {
        // 获取标识
        String tarId = jsonObject.getString("tarId");
        //新增影像
        String newImage = jsonObject.getString("newImage");
        //基准
        String baseImage = jsonObject.getString("baseImage");
        JSONObject json = new JSONObject();
        json.put("id", "1733020058701004800");
        json.put("position", Arrays.asList(127.76962171789036, 26.354828541107505, 300));
        return JSON.toJSONString(R.data(json));
    }

    @Override
    public String imgUpload(JSONObject jsonObject) {
        // 获取标识
        String tarId = jsonObject.getString("tarId");
        // 获取名称
        String imgName = jsonObject.getString("imgName");
        // 获取文件地址
        String imgUrl = jsonObject.getString("imgUrl");
        // 获取类型
        String type = jsonObject.getString("type");
        if (ImageTypeConstant.ENHANCEMENTS != Integer.parseInt(type)) {
            if (StringUtils.isBlank(imgUrl)) {
                return JSON.toJSONString(R.fail("请上传文件"));
            }
            String substring = imgUrl.substring(imgUrl.lastIndexOf("."));
            switch (substring) {
                case ".tif":
                case ".tiff":
                    break;
                default:
                    return JSON.toJSONString(R.fail("请上传正确的影像文件"));
            }
            if (Integer.parseInt(type) < 2) {
                gdalService.tifCut(tarId, imgUrl, Integer.parseInt(type), imgName);
            }
            return JSON.toJSONString(R.success("操作成功"));
        }
        ImageResult imageResult = imageResultService.findByRelId(tarId);
        if (ObjectUtil.isEmpty(imageResult)) {
            imageResult = new ImageResult();
            imageResult.setRelId(tarId);
            imageResult.setCreateTime(LocalDateTime.now());
            imageResult.setId(IdUtil.simpleUUID());
        }
        imageResult.setImageUrl(imgUrl);
        imageResult.setImageName(imgName);
        imageResult.setImageType(String.valueOf(4));
        imageResult.setUpdateTime(LocalDateTime.now());
        // TODO：添加人
        imageResult.setCreatePersion(CommonUtil.getUserId());
        imageResultService.saveOrUpdate(imageResult);
        return JSON.toJSONString(R.success("操作成功"));
    }

    @Override
    public String serImgList(JSONObject jsonObject) {
        //jsonobject解析获取页码
        Integer pageNum = jsonObject.getInteger("pageNum");
        //jsonobject解析获取页容
        Integer pageSize = jsonObject.getInteger("pageSize");
        // 获取标识
        String tarId = jsonObject.getString("tarId");
        // 获取类型
        String type = jsonObject.getString("type");
        Page<ImageCut> page = new Page<>(pageNum, pageSize);
        Page<ImageCut> imageCutPage = imageCutService.lambdaQuery()
                .eq(ImageCut::getRedId, tarId)
                .eq(ImageCut::getImageType, type)
                .orderByDesc(ImageCut::getCreateTime)
                .page(page);
        Map<String, Object> resultMap = new HashMap<>();
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(imageCutPage.getRecords())) {
            Map<String, Object> map;
            for (ImageCut imageCut : imageCutPage.getRecords()) {
                map = new HashMap<>();
                map.put("id", imageCut.getId());
                map.put("imgName", imageCut.getRemark());
                map.put("uploadTime", imageCut.getCreateTime().format(formatter));
                map.put("thumbUrl", keyWordSystem.getSERVER_URL() + imageCut.getThumb());
                map.put("imgUrl", keyWordSystem.getSERVER_URL() + imageCut.getImage());
                map.put("position", JSONArray.parseArray(imageCut.getPosition()));
                resultList.add(map);
            }
        }
        String redisKey = "REDIS_IMAGES_";
        if ("0".equals(type)) {
            redisKey += "BASE";
        } else if ("1".equals(type)) {
            redisKey += "NEW";
        } else {
            redisKey += "RESULT";
        }
        if (redisUtil.hasKey(tarId + redisKey)) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", "");
            map.put("imgName", "影像正常处理中，请稍后");
            map.put("uploadTime", "");
            map.put("thumbUrl", "");
            map.put("imgUrl", "");
            map.put("position", new JSONArray());
            resultList.add(map);
        }
        resultMap.put("imgList", resultList);
        resultMap.put("pageNum", imageCutPage.getCurrent());
        resultMap.put("pageSize", imageCutPage.getSize());
        resultMap.put("pageAll", imageCutPage.getPages());
        resultMap.put("total", imageCutPage.getTotal());
        return JSON.toJSONString(R.data(resultMap));
    }

    @Override
    public String othImgList() {
        return JSON.toJSONString(R.data(new JSONArray(), "无数据"));
    }

    @Override
    public String pointCorrect(JSONObject jsonObject, HttpServletRequest request) {
        String userId = redisUseService.getUserId(request.getHeader("Id"));
        if (redisUtil.hasKey("POINT_CORRECT_" + userId)) {
            return JSON.toJSONString(R.data(new JSONArray(), "选点匹配中，请勿重复操作"));
        } else {
            redisUtil.set("POINT_CORRECT_" + userId, "1", 60 * 60);
        }
        try {
            // 获取标识
            String tarId = jsonObject.getString("tarId");
            // 获取控制点
            JSONArray pointListOne = jsonObject.getJSONArray("pointListOne");
            JSONArray pointListTwo = jsonObject.getJSONArray("pointListTwo");
            //新增影像
            String newImage = jsonObject.getString("newImage");
            //基准
            String baseImage = jsonObject.getString("baseImage");
            //控制点判断
            if (CollectionUtil.isEmpty(pointListOne) || CollectionUtil.isEmpty(pointListTwo)) {
                return JSON.toJSONString(R.fail("请在图上选择控制点"));
            }
            {
                int count = pointListOne.size();
                if (count > pointListTwo.size()) {
                    count = pointListTwo.size();
                }
                int sign = 0;
                for (int i = 0; i < count; i++) {
                    JSONObject object = pointListOne.getJSONObject(i);
                    JSONObject objects = pointListTwo.getJSONObject(i);
                    if (ObjectUtil.isNotEmpty(object.getJSONArray("position"))
                            && ObjectUtil.isNotEmpty(objects.getJSONArray("position"))) {
                        sign++;
                    }
                }
                if (sign < 4) {
                    return JSON.toJSONString(R.fail("图上选择控制点不能小于4个，请重新选择"));
                }
            }
            //选点匹配
            taskRunMapper.delete(new LambdaUpdateWrapper<TaskRun>().eq(TaskRun::getTaskId, tarId).eq(TaskRun::getUserId, userId).eq(TaskRun::getTaskType, "POINT"));
            TaskRun taskRun = new TaskRun();
            taskRun.setId(snow.next().toString());
            taskRun.setTaskId(tarId);
            taskRun.setUserId(userId);
            taskRun.setBaseId(baseImage);
            taskRun.setNewId(newImage);
            taskRun.setTaskType("POINT");
            String tifPoints = gdalService.tifPoints(taskRun, pointListOne, pointListTwo);
            if (StringUtils.isNotEmpty(tifPoints)) {
                ImageCut imageCut = imageCutService.getById(tifPoints);
                JSONObject json = new JSONObject();
                json.put("id", imageCut.getId());
                json.put("position", JSONArray.parseArray(imageCut.getPosition()));
                return JSON.toJSONString(R.data(json, "操作成功"));
            }
            return JSON.toJSONString(R.fail("选点匹配异常"));
        } finally {
            redisUtil.del("POINT_CORRECT_" + userId);
        }
    }

    @Override
    public String test(JSONObject jsonObject, HttpServletRequest request) {
        //jsonobject解析获取标识
        String userId = redisUseService.getUserId(request.getHeader("Id"));
        String tarId = jsonObject.getString("tarId");
        TaskRun taskRun = taskRunMapper.selectOne(new LambdaQueryWrapper<TaskRun>()
                .eq(TaskRun::getTaskId, tarId)
                .eq(TaskRun::getUserId, userId)
                .eq(TaskRun::getTaskType, "AUTO")
                .eq(TaskRun::getTaskStatus, "DONE").last("LIMIT 1"));
        if (ObjectUtil.isNull(taskRun)) {
            taskRun = taskRunMapper.selectOne(new LambdaQueryWrapper<TaskRun>()
                    .eq(TaskRun::getTaskId, tarId)
                    .eq(TaskRun::getUserId, userId)
                    .eq(TaskRun::getTaskType, "POINT")
                    .eq(TaskRun::getTaskStatus, "DONE")
                    .last("LIMIT 1"));
        }
        if (ObjectUtil.isNotEmpty(taskRun)) {
            JSONObject resultJson = new JSONObject();
            resultJson.put("newImage", MyUtil.verityString(taskRun.getNewId()));
            String newUrl = "";
            if (StringUtils.isNotBlank(taskRun.getNewId())) {
                ImageCut imageCut = imageCutService.getById(taskRun.getNewId());
                if (ObjectUtil.isNotEmpty(imageCut)) {
                    newUrl = imageCut.getImage();
                }
            }
            resultJson.put("newUrl", newUrl);
            String baseUrl = "";
            resultJson.put("baseImage", MyUtil.verityString(taskRun.getBaseId()));
            if (StringUtils.isNotBlank(taskRun.getBaseId())) {
                ImageCut imageCut = imageCutService.getById(taskRun.getBaseId());
                if (ObjectUtil.isNotEmpty(imageCut)) {
                    baseUrl = imageCut.getImage();
                }
            }
            resultJson.put("baseUrl", baseUrl);
            String autoUrl = "";
            resultJson.put("autoImage", MyUtil.verityString(taskRun.getResultId()));
            if (StringUtils.isNotBlank(taskRun.getResultId())) {
                ImageCut imageCut = imageCutService.getById(taskRun.getResultId());
                if (ObjectUtil.isNotEmpty(imageCut)) {
                    autoUrl = imageCut.getImage();
                }
            }
            resultJson.put("autoUrl", autoUrl);
            String pointUrl = "";
            resultJson.put("pointImage", MyUtil.verityString(taskRun.getResultId()));
            if (StringUtils.isNotBlank(taskRun.getResultId())) {
                ImageCut imageCut = imageCutService.getById(taskRun.getResultId());
                if (ObjectUtil.isNotEmpty(imageCut)) {
                    pointUrl = imageCut.getImage();
                }
            }
            resultJson.put("pointUrl", pointUrl);
            return JSON.toJSONString(R.data(resultJson));
        }
        return JSON.toJSONString(R.fail("请上传影像，并进行自动或选点匹配"));
    }

    @Override
    public String exportPrecision(JSONObject jsonObject, HttpServletRequest request) {
        // 获取标识
        String tarId = jsonObject.getString("tarId");
        String userId = redisUseService.getUserId(request.getHeader("Id"));
        FileTable fileTable = fileTableService.lambdaQuery()
                .eq(FileTable::getRelId, tarId)
                .eq(FileTable::getCreatePersion, userId)
                .orderByDesc(FileTable::getCreateTime)
                .last("LIMIT 1")
                .one();
        if (ObjectUtil.isEmpty(fileTable)) {
            return JSON.toJSONString(R.fail("不存在此记录"));
        }
        JSONObject json = new JSONObject();
        json.put("fileUrl", keyWordSystem.getSERVER_URL() + fileTable.getFileUrl());
        return JSON.toJSONString(R.data(json));
    }

    public Map<String, String> getPoint(String filePath) {
        Map<String, String> result = new HashMap<>();
        result.put("referencePrecision", "");
        result.put("resultRrror", "");
        result.put("resultPrecision", "");
        String readString = FileUtil.readString(filePath, StandardCharsets.UTF_8);
        JSONObject json = JSONObject.parseObject(readString);
        System.out.println(json.toJSONString());
        {
            BigDecimal bigDecimal = new BigDecimal(json.getJSONArray("Ori Accuracy").getDouble(0) * 10000);
            result.put("referencePrecision", bigDecimal.setScale(6,BigDecimal.ROUND_HALF_UP).toString());
        }
        result.put("resultRrror", FileElseUtil.getObjectToDouble(json.getDouble("MSE")) + "");
        {
            BigDecimal bigDecimal = new BigDecimal(json.getJSONArray("Res Accuracy").getDouble(0) * 10000);
            result.put("resultPrecision", bigDecimal.setScale(6,BigDecimal.ROUND_HALF_UP).toString());
        }
        return result;
    }

    @Override
    public String precisionSave(JSONObject jsonObject, HttpServletRequest request) {
        // 获取标识
        String userId = redisUseService.getUserId(request.getHeader("Id"));
        String tarId = jsonObject.getString("tarId");
        try {
            boolean auto = true;
            TaskRun taskRun = taskRunMapper.selectOne(new LambdaQueryWrapper<TaskRun>()
                    .eq(TaskRun::getTaskId, tarId)
                    .eq(TaskRun::getUserId, userId)
                    .eq(TaskRun::getTaskType, "AUTO")
                    .eq(TaskRun::getTaskStatus, "DONE").last("LIMIT 1"));
            if (ObjectUtil.isNull(taskRun)) {
                taskRun = taskRunMapper.selectOne(new LambdaQueryWrapper<TaskRun>()
                        .eq(TaskRun::getTaskId, tarId)
                        .eq(TaskRun::getUserId, userId)
                        .eq(TaskRun::getTaskType, "POINT")
                        .eq(TaskRun::getTaskStatus, "DONE")
                        .last("LIMIT 1"));
                auto = false;
            }
            if (ObjectUtil.isNull(taskRun)) {
                return JSON.toJSONString(R.fail("暂无成果数据"));
            }
            InputStream ins = this.getClass().getResourceAsStream("/精度报告模板.docx");
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
                    TemplateEngineKind.Freemarker);
            IContext context = report.createContext();
            // 创建要替换的文本变量
            FieldsMetadata fieldsMetadata = report.createFieldsMetadata();
            //图片处理
            ImageCut byId = imageCutService.getById(taskRun.getBaseId());

            fieldsMetadata.addFieldAsImage("baseData");
            IImageProvider imageProvider = new FileImageProvider(new File(keyWordSystem.getFILE_URL() + byId.getImage()));
            context.put("baseData", imageProvider);
            ImageCut byId1 = imageCutService.getById(taskRun.getNewId());
            fieldsMetadata.addFieldAsImage("newData");
            IImageProvider imageProvider1 = new FileImageProvider(new File(keyWordSystem.getFILE_URL() + byId1.getImage()));
            context.put("newData", imageProvider1);
            ImageCut byId2 = imageCutService.getById(taskRun.getResultId());
            fieldsMetadata.addFieldAsImage("resultData");
            IImageProvider imageProvider2 = new FileImageProvider(new File(keyWordSystem.getFILE_URL() + byId2.getImage()));
            context.put("resultData", imageProvider2);
            report.setFieldsMetadata(fieldsMetadata);
            String referencePrecision = "0.00003 m";
            String resultRrror = "6.67766 pixel";
            String resultPrecision = "0.00002 m";
            if (auto) {
                Map<String, String> data = getData(keyWordSystem.getFILE_URL() + taskRun.getResultUrl() + "/mch_report.txt");
                referencePrecision = data.get("referencePrecision");
                resultRrror = data.get("resultRrror");
                resultPrecision = data.get("resultPrecision");
            } else {
                Map<String, String> data = getPoint(keyWordSystem.getFILE_URL() + taskRun.getResultUrl() + "/res.txt");
                referencePrecision = data.get("referencePrecision");
                resultRrror = data.get("resultRrror");
                resultPrecision = data.get("resultPrecision");
            }
            context.put("referencePrecision", referencePrecision);
            context.put("resultRrror", resultRrror);
            context.put("resultPrecision", resultPrecision);
            RepacigiBaseTable repacigiBaseTable = repacigiBaseTableService.lambdaQuery()
                    .eq(RepacigiBaseTable::getTypeId, tarId)
                    .one();
            // 输出到本地目录
            String fileName = repacigiBaseTable.getTypeName() + "_精度报告_" + DateUtils.getDay();
            File file = new File(keyWordSystem.getFILE_URL() + "/file/" + fileName + ".docx");
            FileOutputStream out = new FileOutputStream(file);
            report.process(context, out);
            FileTable fileTable = new FileTable();
            fileTable.setRelId(tarId);
            fileTable.setName(FileUtil.getName(fileName));
            fileTable.setFileSize(String.valueOf(file.length()));
            fileTable.setType("1");
            fileTable.setFileUrl("/file/" + fileName + ".docx");
            fileTable.setCreatePersion(redisUseService.getUserId(request.getHeader("Id")));
            // todo:添加人
            fileTableService.save(fileTable);
        } catch (Exception e) {
            return JSON.toJSONString(R.fail("保存报告异常，请稍后重试"));
        }
        return JSON.toJSONString(R.success("操作成功"));
    }

    public Map<String, String> getData(String filePath) {
        Map<String, String> result = new HashMap<>();
        result.put("referencePrecision", "");
        result.put("resultRrror", "");
        result.put("resultPrecision", "");
        List<String> list = FileUtil.readLines(filePath, StandardCharsets.UTF_8);
        int line = 0;
        for (String s : list) {
            if (1 == line) {
                result.put("resultRrror", s.split("=")[1].trim());
            } else if (3 == line) {
                result.put("referencePrecision", s.split("=")[1].trim());
            } else if (4 == line) {
                result.put("resultPrecision", s.split("=")[1].trim());
            }
            line++;
        }
        return result;
    }

//    public Map<String, String> getData(String url) {
//
//    }

    @Override
    public Result correctSave(JSONObject jsonObject, HttpServletRequest request) {
        //jsonobject解析获取标识
        String userId = redisUseService.getUserId(request.getHeader("Id"));
        String tarId = jsonObject.getString("tarId");
        TaskRun taskRun = taskRunMapper.selectOne(new LambdaQueryWrapper<TaskRun>()
                .eq(TaskRun::getTaskId, tarId)
                .eq(TaskRun::getUserId, userId)
                .eq(TaskRun::getTaskType, "AUTO")
                .eq(TaskRun::getTaskStatus, "DONE").last("LIMIT 1"));
        if (ObjectUtil.isNull(taskRun)) {
            taskRun = taskRunMapper.selectOne(new LambdaQueryWrapper<TaskRun>()
                    .eq(TaskRun::getTaskId, tarId)
                    .eq(TaskRun::getUserId, userId)
                    .eq(TaskRun::getTaskType, "POINT")
                    .eq(TaskRun::getTaskStatus, "DONE")
                    .last("LIMIT 1"));
        }
        if (ObjectUtil.isNull(taskRun)) {
            return ResultUtil.error(500, "暂无配准影像数据");
        }
        ImageResult result = new ImageResult();
        result.setRelId(taskRun.getTaskId());
        result.setImageName("配准影像" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss"));
        result.setImageType("0");
        ImageCut imageCut = imageCutService.getById(taskRun.getBaseId());
        result.setImageUrl(imageCut.getImageUrl());
        result.setImageThumb(imageCut.getImage());
        result.setThumb(imageCut.getThumb());
        ImageCut resultCut = imageCutService.getById(taskRun.getResultId());
        result.setImageRelease(resultCut.getId());
        result.setResultUrl(resultCut.getImageUrl());
        result.setResultThumb(resultCut.getThumb());
        result.setResultRelease(resultCut.getImage());
        result.setCreatePersion(userId);
        imageResultService.save(result);
        return ResultUtil.success("成果保存成功", null);
    }

    @Override
    public String correctList(JSONObject jsonObject) {
        //jsonobject解析获取页码
        Integer pageNum = jsonObject.getInteger("pageNum");
        //jsonobject解析获取页容
        Integer pageSize = jsonObject.getInteger("pageSize");
        //jsonobject解析获取名称
        String imgName = jsonObject.getString("imgName");
        //jsonobject解析获取类型
        String type = jsonObject.getString("type");
        //jsonobject解析获取目标ID
        String tarId = jsonObject.getString("tarId");
        QueryWrapper<ImageCut> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ImageCut::getImageType, type);
        wrapper.lambda().eq(ImageCut::getRedId, tarId);
        if (StringUtils.isNotBlank(imgName)) {
            wrapper.lambda().like(ImageCut::getRemark, imgName);
        }
        wrapper.lambda().orderByDesc(ImageCut::getCreateTime);
        Page<ImageCut> page = imageCutService.page(new Page<>(pageNum, pageSize), wrapper);
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(page.getRecords())) {
            Map<String, Object> map;
            //封装数据
            for (ImageCut record : page.getRecords()) {
                map = new HashMap<>();
                map.put("id", record.getId());
                map.put("imgUrl", keyWordSystem.getSERVER_URL() + record.getThumb());
                map.put("position", StringUtils.isNotBlank(record.getPosition()) ? JSONArray.parseArray(record.getPosition()) : new JSONArray());
                map.put("imgName", StringUtils.isNotBlank(record.getRemark()) ? record.getRemark() : "影像数据");
                LocalDate localDate = record.getCreateTime().toLocalDate();
                Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
                map.put("updateTime", DateUtils.getDay(date));
                resultList.add(map);
            }
        }
        String redisKey = "REDIS_IMAGES_";
        if ("0".equals(type)) {
            redisKey += "BASE";
        } else if ("1".equals(type)) {
            redisKey += "NEW";
        } else {
            redisKey += "RESULT";
        }
        if (redisUtil.hasKey(tarId + redisKey)) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", "");
            map.put("imgName", "影像正常处理中，请稍后");
            map.put("uploadTime", "");
            map.put("imgUrl", "");
            map.put("position", new JSONArray());
            resultList.add(map);
        }
        JSONObject json = new JSONObject();
        json.put("total", page.getTotal());
        json.put("pageAll", page.getPages());
        json.put("pageNum", page.getCurrent());
        json.put("pageSize", page.getSize());
        json.put("imgList", resultList);
        return JSON.toJSONString(R.data(json));
    }

    @Async
    @Override
    public void autoRecognition(String userId, String imgId, JSONArray positions) {
        JSONObject json = new JSONObject();
        if (CollectionUtil.isEmpty(positions)) {
            json.put("code", "AUTO_RECOGNITION_ERROR");
            json.put("message", "请选择识别的范围！");
            webSocketServer.sendToOneByUserId(userId, json.toString());
            return;
        }
        ImageCut imageCut = imageCutService.getById(imgId);
        if (ObjectUtil.isNull(imageCut)) {
            JSON.toJSONString(R.fail("影像不存在/已删除！"));
        }
        System.out.println("positions:" + positions);
        //调用识别算法
        JSONObject discern = gdalService.autoDiscern(imageCut, positions);
        if (ObjectUtil.isNull(discern)) {
            json.put("code", "AUTO_RECOGNITION_ERROR");
            json.put("message", "影像识别异常，请重试！");
            webSocketServer.sendToOneByUserId(userId, json.toString());
            return;
        }
        System.out.println("discern:" + discern);
        //获取识别后坐标
        JSONArray array = discern.getJSONArray("positions");
        if (CollectionUtil.isEmpty(array)) {
            json.put("code", "AUTO_RECOGNITION_ERROR");
            json.put("message", "暂未识别到目标信息");
            webSocketServer.sendToOneByUserId(userId, json.toString());
            return;
        }
        List<RecognitionTable> tables = new ArrayList<>();
        try {
            for (int i = 0; i < array.size(); i++) {
                JSONArray jsonArray = array.getJSONArray(i);
                RecognitionTable table = new RecognitionTable();
                table.setRedId(imgId);
                //经纬度坐标系转换
                double lngMin = jsonArray.getJSONArray(0).getDouble(0);
                double lngMax = jsonArray.getJSONArray(1).getDouble(0);
                double latMin = jsonArray.getJSONArray(1).getDouble(1);
                double latMax = jsonArray.getJSONArray(0).getDouble(1);
                //封装数据为多边形
                table.setName(FileElseUtil.getObjectToString(jsonArray.getString(2)));
                table.setPositions(MyUtil.getBox(
                        lngMin,
                        latMax,
                        lngMax,
                        latMin
                ).toJSONString());
                //计算长宽
                double distance = LngLatUtil.getDistance(lngMin, latMax, lngMax, latMax) * 1000;
                double distance1 = LngLatUtil.getDistance(lngMin, latMax, lngMin, latMin) * 1000;
                if (distance >= distance1) {
                    table.setLength(FileElseUtil.getObjectToDouble(discern) + "");
                    table.setWidth(FileElseUtil.getObjectToDouble(distance1) + "");
                } else {
                    table.setLength(FileElseUtil.getObjectToDouble(distance1) + "");
                    table.setWidth(FileElseUtil.getObjectToDouble(distance) + "");
                }
                //计算中心点坐标
                LinkedList<LngLatUtil.Position> postionList = new LinkedList<>();
                postionList.add(new LngLatUtil.Position(latMax, lngMin));
                postionList.add(new LngLatUtil.Position(latMax, lngMax));
                postionList.add(new LngLatUtil.Position(latMin, lngMax));
                postionList.add(new LngLatUtil.Position(latMin, lngMin));
                Map<String, Double> point = LngLatUtil.getCenterPoint(postionList);
                table.setLon(point.get("centerLon").toString());
                table.setLat(point.get("centerLat").toString());
                tables.add(table);
            }
            recognitionTableService.lambdaUpdate().eq(RecognitionTable::getRedId, imgId).remove();
            recognitionTableService.saveBatch(tables);
        } catch (Exception e) {
            log.error("影像识别异常:{}", e.getMessage(), e);
            json.put("code", "AUTO_RECOGNITION_ERROR");
            json.put("message", "影像识别异常，请重试！");
            webSocketServer.sendToOneByUserId(userId, json.toString());
            return;
        }
        json.put("code", "AUTO_RECOGNITION_SUCCESS");
        json.put("message", tables);
        webSocketServer.sendToOneByUserId(userId, json.toString());
    }

    @Override
    public Result updateRecognition(RecognitionTable table) {
        if (StringUtils.isNotBlank(table.getPositions())) {
            JSONArray array = JSONArray.parseArray(table.getPositions());
            if (CollectionUtil.isNotEmpty(array)) {
                //计算中心点坐标
                LinkedList<LngLatUtil.Position> postionList = new LinkedList<>();
                for (int i = 0; i < array.size(); i++) {
                    JSONArray jsonArray = array.getJSONArray(i);
                    postionList.add(new LngLatUtil.Position(jsonArray.getDouble(1), jsonArray.getDouble(0)));
                }
                Map<String, Double> point = LngLatUtil.getCenterPoint(postionList);
                table.setLon(point.get("centerLon").toString());
                table.setLat(point.get("centerLat").toString());
            }
        }
        recognitionTableService.updateById(table);
        JSONObject resultJson = new JSONObject();
        resultJson.put("code", 200);
        return ResultUtil.success("修改成功", resultJson);
    }

    @Override
    public Result deleteRecognition(JSONObject jsonObject) {
        String id = jsonObject.getString("id");
        boolean remove = recognitionTableService.removeById(id);
        if (remove) {
            JSONObject resultJson = new JSONObject();
            resultJson.put("code", 200);
            return ResultUtil.success("删除成功", resultJson);
        }
        JSONObject resultJson = new JSONObject();
        resultJson.put("code", 500);
        return ResultUtil.error(500, "已删除/不存在", resultJson);
    }

    @Override
    public Result deleteRecognitionAll(JSONObject jsonObject) {
        String id = jsonObject.getString("imgId");
        recognitionTableService.lambdaUpdate().eq(RecognitionTable::getRedId, id).remove();
        JSONObject resultJson = new JSONObject();
        resultJson.put("code", 200);
        return ResultUtil.success("清除成功", resultJson);
    }

    @Override
    public Result exportMb(JSONObject jsonObject) {
        // 获取标识
        String tarId = jsonObject.getString("tarId");
        FileTable fileTable = fileTableService.lambdaQuery()
                .eq(FileTable::getRelId, tarId)
                .orderByDesc(FileTable::getCreateTime)
                .last("LIMIT 1")
                .one();
        if (ObjectUtil.isEmpty(fileTable)) {
            return ResultUtil.error(500, "请先保存报告数据");
        }
        JSONObject json = new JSONObject();
        json.put("fileUrl", keyWordSystem.getSERVER_URL() + fileTable.getFileUrl());
        return ResultUtil.success(json);
    }

    @Override
    public Result mbSave(JSONObject jsonObject, HttpServletRequest request) throws IOException, XDocReportException {
        // 获取标识
        String tarId = jsonObject.getString("tarId");
//        String imgId = jsonObject.getString("imgId");
        RepacigiMainTable repacigiMainTable = repacigiMainTableService.lambdaQuery()
                .eq(RepacigiMainTable::getTarId, tarId)
                .one();
        if (ObjectUtil.isEmpty(repacigiMainTable)) {
            return ResultUtil.error(500, "当前目标不存在，请重新选择");
        }
//        ImageCut imageCut = imageCutService.getById(imgId);
//        if (ObjectUtil.isEmpty(imageCut)) {
//            return ResultUtil.error(500, "当前影像不存在，请重新选择");
//        }
        InputStream ins = this.getClass().getResourceAsStream("/M指报告模板.docx");
        IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
                TemplateEngineKind.Freemarker);
        IContext context = report.createContext();
        // 创建要替换的文本变量
        context.put("tarName", StringUtils.isBlank(repacigiMainTable.getTarName()) ? "" : repacigiMainTable.getTarName());
        if (FileElseUtil.isDouble(repacigiMainTable.getLon()) && FileElseUtil.isDouble(repacigiMainTable.getLat())) {
            double lon = FileElseUtil.getStringTransitionDouble(repacigiMainTable.getLon());
            double lat = FileElseUtil.getStringTransitionDouble(repacigiMainTable.getLat());
            context.put("position", lon + "," + lat);
            Map<String, Double> map = LngLatUtil.WGS84ToCGCS2000(lon, lat);
            context.put("lon", map.get("lon"));
            context.put("lat", map.get("lat"));
        } else {
            context.put("position", "");
            context.put("lon", "");
            context.put("lat", "");
        }
        context.put("geoHeight", FileElseUtil.getObjectToString(repacigiMainTable.getGeoHeight()));
        context.put("altitude", FileElseUtil.getObjectToString(repacigiMainTable.getAltitude()));
        context.put("area", FileElseUtil.getObjectToString(repacigiMainTable.getArea()));
        context.put("remark", FileElseUtil.getObjectToString(repacigiMainTable.getRemark()));
        // 查询子目标
//        String imgPosition = imageCut.getImgPosition();
        List<RepacigiSubTable> repacigiSubTables = repacigiSubTableService.lambdaQuery()
                .eq(RepacigiSubTable::getTargetId, tarId)
                .list();
//        List<RepacigiSubTable> repacigiSubTables = new ArrayList<>();
        if (CollectionUtil.isEmpty(repacigiSubTables)) {
            RepacigiSubTable subTable = new RepacigiSubTable();
            subTable.setSubName("");
            subTable.setPosition("");
            subTable.setLon("");
            subTable.setLat("");
            subTable.setGeoHeight("");
            subTable.setAltitude("");
            subTable.setArea("");
            subTable.setStructureType("");
            subTable.setRemark("");
            repacigiSubTables.add(subTable);
        } else {
//            JSONArray array = JSONArray.parseArray(imgPosition);
//            for (int i = 0; i < array.size(); i++) {
//                JSONObject json = array.getJSONObject(i);
//                RepacigiSubTable subTable = new RepacigiSubTable();
//                subTable.setSubName(FileElseUtil.getObjectToString(json.getString("name")));
//                subTable.setPosition("");
//                subTable.setLon("");
//                subTable.setLat("");
//                subTable.setGeoHeight("");
//                subTable.setAltitude("");
//                subTable.setArea("");
//                subTable.setStructureType("");
//                subTable.setRemark("");
//                repacigiSubTables.add(subTable);
//            }
            for (RepacigiSubTable subTable : repacigiSubTables) {
                subTable.setSubName(FileElseUtil.getObjectToString(subTable.getSubName()));
                if (FileElseUtil.isDouble(subTable.getLon()) && FileElseUtil.isDouble(subTable.getLat())) {
                    double lon = FileElseUtil.getStringTransitionDouble(subTable.getLon());
                    double lat = FileElseUtil.getStringTransitionDouble(subTable.getLat());
                    subTable.setPosition(lon + "," + lat);
                    Map<String, Double> map = LngLatUtil.WGS84ToCGCS2000(lon, lat);
                    subTable.setLon(map.get("lon").toString());
                    subTable.setLat(map.get("lat").toString());
                } else {
                    subTable.setPosition("");
                    subTable.setLon("");
                    subTable.setLat("");
                }
                subTable.setGeoHeight(FileElseUtil.getObjectToString(subTable.getGeoHeight()));
                subTable.setAltitude(FileElseUtil.getObjectToString(subTable.getAltitude()));
                subTable.setArea(FileElseUtil.getObjectToString(subTable.getArea()));
                subTable.setStructureType(FileElseUtil.getObjectToString(subTable.getStructureType()));
                subTable.setRemark(FileElseUtil.getObjectToString(subTable.getRemark()));
            }
        }
        context.put("item", repacigiSubTables);
        FieldsMetadata fm = report.createFieldsMetadata();
        fm.load("item", RepacigiSubTable.class, true);
        // 输出到本地目录
        String fileName = repacigiMainTable.getTarName() + "_目指报告_" + DateUtils.getDay();
        File file = new File(keyWordSystem.getFILE_URL() + "/doc/" + fileName + ".docx");
        FileOutputStream out = new FileOutputStream(file);
        report.process(context, out);
        FileTable fileTable = new FileTable();
        fileTable.setRelId(tarId);
        fileTable.setName(FileUtil.getName(fileName));
        fileTable.setFileSize(String.valueOf(file.length()));
        fileTable.setType("0");
        fileTable.setFileUrl("/doc/" + fileName + ".docx");
        // todo:添加人
        fileTable.setCreatePersion(redisUseService.getUserId(request.getHeader("Id")));
        fileTableService.save(fileTable);
        return ResultUtil.success("保存成功", null);
    }

    @Override
    public Result recognitionSave(RecognitionVo recognitionVo, HttpServletRequest request) {
        ImageCut imageCut = imageCutService.getById(recognitionVo.getImgId());
        if (ObjectUtil.isEmpty(imageCut)) {
            return ResultUtil.error(500, "当前影像不存在，请重新选择影像。");
        }
        Integer count = recognitionTableService.lambdaQuery().eq(RecognitionTable::getRedId, recognitionVo.getImgId()).count();
        if (0 == count) {
            return ResultUtil.error(500, "暂无识别的数据，请识别后重试");
        }
        String id = request.getHeader("Id");
        String userId = redisUseService.getUserId(id);
        ImageResult result = new ImageResult();
        result.setRelId(imageCut.getRedId());
        result.setImageName("识别影像" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss"));
        result.setImageType("1");
        result.setImageUrl(imageCut.getImageUrl());
        result.setImageThumb(imageCut.getImage());
        result.setImageRelease(imageCut.getId());
        result.setThumb(imageCut.getThumb());
        result.setCreatePersion(userId);
        tiffUtilService.saveRecognition(result, imageCut.getImageUrl(), recognitionVo.getImgId());
        return ResultUtil.success("保存识别成果中", null);
    }

    @Override
    public Result subject(JSONObject jsonObject, HttpServletRequest request) {
        // 获取标识
        String tarId = redisUseService.getUserId(request.getHeader("Id"));
        ImageSpecialSubject imageSpecialSubject = imageSpecialSubjectService.lambdaQuery().eq(ImageSpecialSubject::getRelId, tarId).one();
        if (ObjectUtil.isEmpty(imageSpecialSubject)) {
            return ResultUtil.error(500, "请先新建一个专题");
        }
        SubjectVO subjectVO = new SubjectVO();
        subjectVO.setImgUrl(imageSpecialSubject.getImgUrl());
        subjectVO.setIntervalLon(imageSpecialSubject.getIntervalLon());
        subjectVO.setIntervalLat(imageSpecialSubject.getIntervalLat());
        subjectVO.setPlotList(imageSpecialSubject.getImgPosition());
        subjectVO.setSubjectName(imageSpecialSubject.getSpecialName());
        subjectVO.setSummarize(imageSpecialSubject.getOverview());
        subjectVO.setTarId(imageSpecialSubject.getRelId());
        subjectVO.setFormat(imageSpecialSubject.getPlateType());
        return ResultUtil.success(subjectVO);
    }

    @Override
    public Result subjectEdit(JSONObject jsonObject, HttpServletRequest request) {
        // 获取标识
//        String tarId = jsonObject.getString("tarId");
        String tarId = redisUseService.getUserId(request.getHeader("Id"));
        // 获取概述
        String summarize = jsonObject.getString("summarize");
        // 获取名称
        String subjectName = jsonObject.getString("subjectName");
        // 获取比例尺
        String scale = jsonObject.getString("scale");
        // 获取图地址
        String imgUrl = jsonObject.getString("imgUrl");
        // 获取标绘信息
        String plotList = jsonObject.getString("plotList");
        // 获取版式
        String format = jsonObject.getString("format");
        String intervalLon = jsonObject.getString("intervalLon");
        String intervalLat = jsonObject.getString("intervalLat");
//        if (StringUtils.isNotBlank(subjectName)) {
//            imageSpecialSubjectService.remove(new LambdaQueryWrapper<ImageSpecialSubject>()
//                    .eq(ImageSpecialSubject::getRelId, tarId));
//            Integer count = imageCutService.lambdaQuery().eq(ImageCut::getRedId, tarId).count();
//            if (count == 0 && StringUtils.isBlank(imgUrl)) {
//                return JSON.toJSONString(R.fail("请先上传一个影像"));
//            } else if (count > 0 && StringUtils.isBlank(imgUrl)) {
//                ImageCut imageCut = imageCutService.lambdaQuery()
//                        .eq(ImageCut::getRedId, tarId)
//                        .orderByDesc(ImageCut::getCreateTime)
//                        .last("LIMIT 1")
//                        .one();
//                ImageSpecialSubject subject = new ImageSpecialSubject();
//                subject.setRelId(tarId);
//                subject.setSpecialName(subjectName);
//                subject.setPlateType(format);
//                subject.setRemark(imageCut.getId());
//                imageSpecialSubjectService.save(subject);
//                JSONObject json = new JSONObject();
//                json.put("position", JSONArray.parseArray(imageCut.getPosition()));
//                json.put("cutId", imageCut.getId());
//                return JSON.toJSONString(R.data(json));
//            } else {
//                Map<String, String> map = gdalService.tifCutLonLat(tarId, imgUrl, ImageTypeConstant.RASTER);
//                if ("0".equals(map.get("code"))) {
//                    return JSON.toJSONString(R.fail(map.get("msg")));
//                }
//                ImageSpecialSubject subject = new ImageSpecialSubject();
//                subject.setRelId(tarId);
//                subject.setSpecialName(subjectName);
//                subject.setPlateType(format);
//                subject.setRemark(map.get("code"));
//                imageSpecialSubjectService.save(subject);
//                JSONObject json = new JSONObject();
//                json.put("position", JSONArray.parseArray(map.get("msg")));
//                json.put("cutId", map.get("code"));
//                return JSON.toJSONString(R.data(json));
//            }
//        } else {
        ImageSpecialSubject imageSpecialSubject = imageSpecialSubjectService
                .lambdaQuery()
                .eq(ImageSpecialSubject::getRelId, tarId)
                .one();
        if (ObjectUtil.isNotEmpty(imageSpecialSubject)) {
            boolean update = false;
            LambdaUpdateWrapper<ImageSpecialSubject> wrapper = new LambdaUpdateWrapper<>();
            if (StringUtils.isNotBlank(summarize)) {
                wrapper.set(ImageSpecialSubject::getOverview, summarize);
                update = true;
            }
            if (StringUtils.isNotBlank(scale)) {
                wrapper.set(ImageSpecialSubject::getScale, scale);
                update = true;
            }
            if (StringUtils.isNotBlank(intervalLon)) {
                wrapper.set(ImageSpecialSubject::getIntervalLon, intervalLon);
                update = true;
            }
            if (StringUtils.isNotBlank(intervalLat)) {
                wrapper.set(ImageSpecialSubject::getIntervalLat, intervalLat);
                update = true;
            }
            if (StringUtils.isNotBlank(plotList)) {
                wrapper.set(ImageSpecialSubject::getGraticule, plotList);
                update = true;
            }
            if (update) {
                wrapper.eq(ImageSpecialSubject::getId, imageSpecialSubject.getId());
                imageSpecialSubjectService.update(wrapper);
                return ResultUtil.success("编辑成功", null);
            }
            return ResultUtil.success("暂无可编辑的内容", null);
        }
//        }
        return ResultUtil.error(500, "请先新建一个专题");
    }

    @Override
    public String griddingEdit(JSONObject jsonObject) {
        // 获取标识
        String tarId = jsonObject.getString("tarId");
        // 获取间隔
        String intervalLon = jsonObject.getString("intervalLon");
        String intervalLat = jsonObject.getString("intervalLat");
        ImageSpecialSubject imageSpecialSubject = imageSpecialSubjectService.lambdaQuery()
                .eq(ImageSpecialSubject::getRelId, tarId).one();
        if (ObjectUtil.isEmpty(imageSpecialSubject)) {
            return JSON.toJSONString(R.fail("记录不存在"));
        }
        imageSpecialSubject.setIntervalLon(intervalLon);
        imageSpecialSubject.setIntervalLat(intervalLat);
        imageSpecialSubjectService.updateById(imageSpecialSubject);
        return JSON.toJSONString(R.success("操作成功"));
    }

    @Override
    public String typeList() {
        List<RepacigiBaseTable> baseTables = repacigiBaseTableMapper.selectList(new LambdaQueryWrapper<RepacigiBaseTable>()
                .eq(RepacigiBaseTable::getParentId, "0")
                .eq(RepacigiBaseTable::getType, "0")
                .orderByAsc(RepacigiBaseTable::getSort));
        List<BaseTypeVO> list = null;
        if (ObjectUtil.isNotEmpty(baseTables)) {
            list = coverToVO(baseTables);
            List<RepacigiBaseTable> tables = repacigiBaseTableMapper.selectList(new LambdaQueryWrapper<RepacigiBaseTable>()
                    .notIn(RepacigiBaseTable::getParentId, "0")
                    .orderByAsc(RepacigiBaseTable::getSort));
            list.parallelStream().forEach(table -> {
                table.setChildren(getBase(tables, table.getTypeId()));
            });
        }
        return JSON.toJSONString(R.data(list));
    }

    private List<BaseTypeVO> getBase(List<RepacigiBaseTable> tables, String typeId) {
        List<BaseTypeVO> list = Lists.newArrayList();
        for (RepacigiBaseTable table : tables) {
            if (table.getParentId().equals(typeId)) {
                list.add(createToVO(table));
            }
        }
        for (BaseTypeVO baseTypeVO : list) {
            baseTypeVO.setChildren(getBase(tables, baseTypeVO.getTypeId()));
        }
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list;
    }

    private BaseTypeVO createToVO(RepacigiBaseTable baseTable) {
        return BaseTypeVO.builder()
                .type(baseTable.getType())
                .level(baseTable.getLevel())
                .typeName(baseTable.getTypeName())
                .typeId(baseTable.getTypeId())
                .build();
    }

    private List<BaseTypeVO> coverToVO(List<RepacigiBaseTable> baseTables) {
        List<BaseTypeVO> list = Lists.newArrayList();
        baseTables.forEach(table -> {
            list.add(BaseTypeVO.builder()
                    .type(table.getType())
                    .level(table.getLevel())
                    .typeName(table.getTypeName())
                    .typeId(table.getTypeId())
                    .build());
        });
        return list;
    }

    @Override
    public String typeEdit(JSONObject jsonObject) {
        //层级
        String level = jsonObject.getString("level");
        //标识
        String typeId = jsonObject.getString("typeId");
        //名称
        String typeName = jsonObject.getString("typeName");
        //父id
        String parentId = jsonObject.getString("pId");
        parentId = StrUtil.isBlank(parentId) ? "0" : parentId;
        if (StrUtil.isBlank(typeId) || typeId.equals("0")) {
            List<RepacigiBaseTable> list = repacigiBaseTableMapper.selectList(new LambdaQueryWrapper<RepacigiBaseTable>()
                    .eq(RepacigiBaseTable::getParentId, parentId)
                    .select(RepacigiBaseTable::getSort)
                    .orderByDesc(RepacigiBaseTable::getSort));
            int sort = 0;
            if (ObjectUtil.isNotEmpty(list)) {
                sort = list.get(0).getSort();
            }
            RepacigiBaseTable baseTable = RepacigiBaseTable.builder()
                    .level(level)
                    .parentId(parentId)
                    .createTime(LocalDateTime.now())
                    .type("0")
                    .typeName(typeName)
                    .sort(sort + 1)
                    .build();
            repacigiBaseTableMapper.insert(baseTable);
            JSONObject js = new JSONObject();
            js.put("typeId", baseTable.getTypeId());
            return JSON.toJSONString(R.data(js, "新增成功"));
        } else {
            RepacigiBaseTable table = repacigiBaseTableMapper.selectById(typeId);
            table.setTypeName(typeName);
            table.setParentId(parentId);
            repacigiBaseTableMapper.updateById(table);
            if ("1".equals(table.getType())) {
                RepacigiMainTable mainTable = repacigiMainTableService.getById(typeId);
                if (ObjectUtil.isNull(mainTable)) {
                    mainTable = new RepacigiMainTable();
                    mainTable.setTarId(typeId);
                }
                mainTable.setTarName(typeName);
                repacigiMainTableService.saveOrUpdate(mainTable);
            }
            return JSON.toJSONString(R.success("更新成功"));
        }
    }

    @Override
    public String subList(JSONObject jsonObject) {
        //MB标识
        String targetId = jsonObject.getString("tarId");
        List<RepacigiSubTable> subTables = repacigiSubTableMapper.selectList(new LambdaQueryWrapper<RepacigiSubTable>()
                .eq(RepacigiSubTable::getTargetId, targetId)
                .orderByAsc(RepacigiSubTable::getUpdateTime));
        List<SubMbBaseTypeVO> subList = Lists.newArrayList();
        subTables.forEach(table -> {
            subList.add(SubMbBaseTypeVO.builder().subId(table.getSubId()).subName(table.getSubName()).build());
        });
        if (ObjectUtil.isNotEmpty(subList)) {
            return JSON.toJSONString(R.data(subList));
        }
        return JSON.toJSONString(R.data(new ArrayList(), "无数据"));
    }

    @Override
    public String subEdit(JSONObject jsonObject) {
        //MB标识
        String tarId = jsonObject.getString("tarId");
        //子MB标识
        String subId = jsonObject.getString("subId");
        //子MB名称
        String subName = jsonObject.getString("subName");
        if (StrUtil.isBlank(subId) || subId.equals("0")) {
            RepacigiSubTable subTable = new RepacigiSubTable();
            subTable.setTargetId(tarId);
            subTable.setSubName(subName);
            repacigiSubTableMapper.insert(subTable);
            return JSON.toJSONString(R.success("新增成功"));
        } else {
            RepacigiSubTable subTable = new RepacigiSubTable();
            subTable.setSubId(subId);
            subTable.setSubName(subName);
            repacigiSubTableMapper.updateById(subTable);
            return JSON.toJSONString(R.success("更新成功"));
        }
    }

    @Override
    public String typeDelete(JSONObject jsonObject) {
        //层级
        String level = jsonObject.getString("level");
        //标识
        String typeId = jsonObject.getString("typeId");
        List<RepacigiBaseTable> list = repacigiBaseTableMapper.selectList(
                new LambdaQueryWrapper<RepacigiBaseTable>()
                        .eq(RepacigiBaseTable::getType, "0")
                        .eq(RepacigiBaseTable::getParentId, typeId));
        if (ObjectUtil.isEmpty(list)) {
            repacigiBaseTableMapper.deleteById(typeId);
            return JSON.toJSONString(R.success("删除成功"));
        } else {
            return JSON.toJSONString(R.fail("删除失败,请先删除子类别！"));
        }
    }

    @Override
    public String subDelete(JSONObject jsonObject) {
        //MB标识
        String tarId = jsonObject.getString("tarId");
        //MB标识
        String subId = jsonObject.getString("subId");
        if (ObjectUtil.isNotEmpty(subId)) {
            repacigiBaseTableMapper.delete(new LambdaQueryWrapper<RepacigiBaseTable>()
                    .eq(RepacigiBaseTable::getType, "1")
                    .eq(StrUtil.isNotBlank(tarId), RepacigiBaseTable::getParentId, tarId)
                    .eq(RepacigiBaseTable::getTypeId, subId)
            );
            return JSON.toJSONString(R.success("删除成功"));
        }
        return JSON.toJSONString(R.success("无数据"));
    }

    @Override
    public String subPlot(JSONObject jsonObject) {
        //jsonobject解析获取MB标识
        String tarId = jsonObject.getString("tarId");
        //jsonobject解析获取子MB标识
        String subId = jsonObject.getString("subId");
        //jsonobject解析获取标绘信息
        String plotList = jsonObject.getString("plotList");
        if (
                "xxx".equals(tarId)
                        &&
                        "xxxx".equals(subId)
                        &&
                        "标绘信息".equals(plotList)
        ) {
            return "{\"msg\":\"操作成功\",\"code\":200,\"data\":{},\"success\":true}";
        }
        if (jsonObject == null || jsonObject.size() < 1
        ) {
            return "";
        }
        return JSON.toJSONString(R.success("无数据"));
    }

    @Override
    public String editMbFast(JSONObject jsonObject) {
        //名称
        String typeName = jsonObject.getString("typeName");
        //标识
        String typeId = jsonObject.getString("typeId");
        //层级
        String level = jsonObject.getString("level");
        //父id
        String parentId = jsonObject.getString("pId");
        parentId = StrUtil.isBlank(parentId) ? "0" : parentId;
        List<RepacigiBaseTable> list = repacigiBaseTableMapper.selectList(new LambdaQueryWrapper<RepacigiBaseTable>()
                .eq(RepacigiBaseTable::getParentId, parentId)
                .select(RepacigiBaseTable::getSort)
                .orderByDesc(RepacigiBaseTable::getSort));
        int sort = 0;
        if (ObjectUtil.isNotEmpty(list)) {
            sort = list.get(0).getSort();
        }
        if (StrUtil.isBlank(typeId) || typeId.equals("0")) {
            RepacigiBaseTable baseTable = new RepacigiBaseTable();
            baseTable.setParentId(parentId);
            baseTable.setTypeName(typeName);
            baseTable.setType("1");
            baseTable.setSort(sort + 1);
            repacigiBaseTableMapper.insert(baseTable);
            RepacigiMainTable mainTable = new RepacigiMainTable();
            mainTable.setTarId(baseTable.getTypeId());
            mainTable.setTarName(typeName);
            repacigiMainTableService.save(mainTable);
            JSONObject js = new JSONObject();
            js.put("typeId", baseTable.getTypeId());
            return JSON.toJSONString(R.data(js, "新增成功"));
        } else {
            repacigiBaseTableService.lambdaUpdate()
                    .set(RepacigiBaseTable::getTypeName, typeName)
                    .eq(RepacigiBaseTable::getTypeId, typeId)
                    .update();
            repacigiMainTableService.lambdaUpdate()
                    .set(RepacigiMainTable::getTarName, typeName)
                    .eq(RepacigiMainTable::getTarId, typeId)
                    .update();
            return JSON.toJSONString(R.success("更新成功"));
        }
    }

    @Override
    public String tarAttributeEditFast(JSONObject jsonObject) {
        //标识
        String tarId = jsonObject.getString("tarId");
        //MB标识
        String tarSign = jsonObject.getString("tarSign");
        //MB识别码
        String tarCode = jsonObject.getString("tarCode");
        //国家地区
        String country = jsonObject.getString("country");
        //MB区
        String tarRegion = jsonObject.getString("tarRegion");
        //MB名称
        String tarName = jsonObject.getString("tarName");
        //MB编号
        String tarSerial = jsonObject.getString("tarSerial");
        //类别
        String tarType = jsonObject.getString("tarType");
        //MB等级
        String tarGradient = jsonObject.getString("tarGradient");
        //成果可信度
        String tarReliability = jsonObject.getString("tarReliability");
        //坐标系
        String coordinateSystem = jsonObject.getString("coordinateSystem");
        //定位点子MB
        String subPosition = jsonObject.getString("subPosition");
        //定位点
        String position = jsonObject.getString("position");
        //经度（度分秒）
        String lon = jsonObject.getString("lon");
        //纬度（度分秒）
        String lat = jsonObject.getString("lat");
        //大地高度（米）
        String geoHeight = jsonObject.getString("geoHeight");
        //海拔高度（米）
        String altitude = jsonObject.getString("altitude");
        //面积（平方米）
        String area = jsonObject.getString("area");
        //备注
        String remark = jsonObject.getString("remark");
        //点位误差（米）
        String pointError = jsonObject.getString("pointError");
        //经度误差（秒）
        String lonError = jsonObject.getString("lonError");
        //纬度误差（秒）
        String latError = jsonObject.getString("latError");
        //大地高误差（米）
        String geoHeightError = jsonObject.getString("geoHeightError");
        //海拔高误差（米）
        String altitudeError = jsonObject.getString("altitudeError");
        //原图误差（米）
        String masterMapError = jsonObject.getString("masterMapError");
        //图制作误差（米）
        String tarMapError = jsonObject.getString("tarMapError");
        //地物加绘误差（米）
        String plotError = jsonObject.getString("plotError");
        //成果密级
        String resultClassification = jsonObject.getString("resultClassification");
        //整编单位
        String reorganizeUnit = jsonObject.getString("reorganizeUnit");
        //整编日期
        String reorganizeDate = jsonObject.getString("reorganizeDate");
        //出版序号
        String publicationNumber = jsonObject.getString("publicationNumber");
        RepacigiMainTable build = RepacigiMainTable.builder().tarId(tarId).tarSign(tarSign).tarCode(tarCode)
                .country(country).tarRegion(tarRegion).tarName(tarName).tarSerial(tarSerial)
                .tarType(tarType).tarGradient(tarGradient).tarReliability(tarReliability)
                .coordinateSystem(coordinateSystem).subPosition(subPosition).position(position)
                .lon(lon).lat(lat).geoHeight(geoHeight).altitude(altitude).area(area)
                .remark(remark).pointError(pointError).lonError(lonError).latError(latError)
                .geoHeightError(geoHeightError).altitudeError(altitudeError).masterMapError(masterMapError)
                .tarMapError(tarMapError).plotError(plotError).resultClassification(resultClassification)
                .reorganizeUnit(reorganizeUnit).reorganizeDate(reorganizeDate).publicationNumber(publicationNumber)
                .build();
        repacigiMainTableService.saveOrUpdate(build);
        repacigiBaseTableService.lambdaUpdate()
                .set(RepacigiBaseTable::getTypeName, tarName)
                .eq(RepacigiBaseTable::getTypeId, build.getTarId())
                .update();
        return JSON.toJSONString(R.success("更新成功"));
    }

    @Override
    public String upNodeFast(JSONObject jsonObject) {
        //类型
        String type = jsonObject.getString("type");
        //标识
        String typeId = jsonObject.getString("typeId");
        RepacigiBaseTable baseTable = repacigiBaseTableMapper.selectById(typeId);
        if (ObjectUtil.isNotEmpty(baseTable)) {
            List<RepacigiBaseTable> tables = repacigiBaseTableMapper.selectList(
                    new LambdaQueryWrapper<RepacigiBaseTable>()
                            .eq(RepacigiBaseTable::getParentId, baseTable.getParentId())
                            .orderByAsc(RepacigiBaseTable::getSort)
            );
            int size = tables.size();
            LinkedHashSet<RepacigiBaseTable> sortTables = Sets.newLinkedHashSet();
            for (int i = 0; i < size; i++) {
                RepacigiBaseTable table = tables.get(i);
                if (typeId.equals(table.getTypeId())) {
                    if ("1".equals(type)) {
                        if (i == 0) {
                            return JSON.toJSONString(R.fail("已经置顶"));
                        } else {
                            sortTables.add(table);
                            sortTables.addAll(tables);
                        }
                    } else if ("4".equals(type)) {
                        if (i == (size - 1)) {
                            return JSON.toJSONString(R.fail("已经置底"));
                        } else {
                            List<RepacigiBaseTable> collect = tables.stream().filter(base -> (!typeId.equals(base.getTypeId()))).collect(Collectors.toList());
                            sortTables.addAll(collect);
                            sortTables.add(table);
                        }
                    } else if ("2".equals(type)) {
                        if (i == 0) {
                            return JSON.toJSONString(R.fail("已经置顶"));
                        } else {
                            RepacigiBaseTable preTable = tables.get(i - 1);
                            Integer preSort = preTable.getSort();
                            preTable.setSort(table.getSort());
                            table.setSort(preSort);
                            sortTables.addAll(tables.stream().sorted(Comparator.comparing(RepacigiBaseTable::getSort)).collect(Collectors.toList()));
                        }
                    } else if ("3".equals(type)) {
                        if (i == (size - 1)) {
                            return JSON.toJSONString(R.fail("已经置底"));
                        } else {
                            RepacigiBaseTable afterTable = tables.get(i + 1);
                            Integer afterSort = afterTable.getSort();
                            afterTable.setSort(table.getSort());
                            table.setSort(afterSort);
                            sortTables.addAll(tables.stream().sorted(Comparator.comparing(RepacigiBaseTable::getSort)).collect(Collectors.toList()));
                        }
                    }
                }
            }
            List<RepacigiBaseTable> sort = Lists.newArrayList(sortTables);
            for (int i = 0; i < sort.size(); i++) {
                sort.get(i).setSort(i);
                repacigiBaseTableMapper.updateById(sort.get(i));
            }
        }
        if ("1".equals(type)) {
            return JSON.toJSONString(R.success("置顶成功"));
        }
        if ("2".equals(type)) {
            return JSON.toJSONString(R.success("上移成功"));
        }
        if ("3".equals(type)) {
            return JSON.toJSONString(R.success("下移成功"));
        }
        if ("4".equals(type)) {
            return JSON.toJSONString(R.success("置底成功"));
        }
        return JSON.toJSONString(R.success("操作成功"));
    }

    @Override
    public String subAttributeEditFast(JSONObject jsonObject) {
        //标识
        String subId = jsonObject.getString("subId");
        //子MB标识
        String subSign = jsonObject.getString("subSign");
        //名称
        String subName = jsonObject.getString("subName");
        //标识码
        String subCode = jsonObject.getString("subCode");
        //类型
        String subType = jsonObject.getString("subType");
        //材质类型
        String materialType = jsonObject.getString("materialType");
        //结构类型
        String structureType = jsonObject.getString("structureType");
        //长度（米）
        String length = jsonObject.getString("length");
        //宽度（米）
        String wide = jsonObject.getString("wide");
        //高度（米）
        String height = jsonObject.getString("height");
        //方位角（度）
        String azimuthAngle = jsonObject.getString("azimuthAngle");
        //圆内半径（米）
        String inRadius = jsonObject.getString("inRadius");
        //圆外半径（米）
        String outRadius = jsonObject.getString("outRadius");
        //坐标系
        String coordinateSystem = jsonObject.getString("coordinateSystem");
        //定位点
        String position = jsonObject.getString("position");
        //经度（度分秒）
        String lon = jsonObject.getString("lon");
        //纬度（度分秒）
        String lat = jsonObject.getString("lat");
        //大地高度（米）
        String geoHeight = jsonObject.getString("geoHeight");
        //海拔高度（米）
        String altitude = jsonObject.getString("altitude");
        //面积（平方米）
        String area = jsonObject.getString("area");
        //备注
        String remark = jsonObject.getString("remark");
        //点位误差（米）
        String pointError = jsonObject.getString("pointError");
        //经度误差（秒）
        String lonError = jsonObject.getString("lonError");
        //纬度误差（秒）
        String latError = jsonObject.getString("latError");
        //大地高误差（米）
        String geoHeightError = jsonObject.getString("geoHeightError");
        //海拔高误差（米）
        String altitudeError = jsonObject.getString("altitudeError");
        //原图误差（米）
        String masterMapError = jsonObject.getString("masterMapError");
        //图制作误差（米）
        String tarMapError = jsonObject.getString("tarMapError");
        //地物加绘误差（米）
        String plotError = jsonObject.getString("plotError");
        RepacigiSubTable build = RepacigiSubTable.builder().subId(subId).subSign(subSign)
                .subName(subName).subCode(subCode).subType(subType).materialType(materialType)
                .structureType(structureType).length(length).wide(wide).height(height)
                .azimuthAngle(azimuthAngle).inRadius(inRadius).outRadius(outRadius)
                .coordinateSystem(coordinateSystem).position(position).lon(lon)
                .lat(lat).geoHeight(geoHeight).altitude(altitude).area(area)
                .remark(remark).pointError(pointError).lonError(lonError).latError(latError)
                .geoHeightError(geoHeightError).altitudeError(altitudeError)
                .masterMapError(masterMapError).tarMapError(tarMapError)
                .plotError(plotError).build();
        repacigiSubTableService.saveOrUpdate(build);
        return JSON.toJSONString(R.success("更新成功"));
    }

    @Override
    public String tarAttributeFast(JSONObject jsonObject) {
        //标识
        String tarId = jsonObject.getString("tarId");
        RepacigiMainTable repacigiMainTable = repacigiMainTableMapper.selectById(tarId);
        if (ObjectUtil.isNotEmpty(repacigiMainTable)) {
            return JSON.toJSONString(R.data(repacigiMainTable));
        }
        return JSON.toJSONString(R.success("无数据"));
    }

    @Override
    public String subAttributeFast(JSONObject jsonObject) {
        //标识
        String subId = jsonObject.getString("subId");
        RepacigiSubTable repacigiSubTable = repacigiSubTableMapper.selectById(subId);
        if (ObjectUtil.isNotEmpty(repacigiSubTable)) {
            return JSON.toJSONString(R.data(repacigiSubTable));
        }
        return JSON.toJSONString(R.success("无数据"));
    }

    public void getSubTable(String outPath, List<RepacigiSubTable> subTables) {
        try {
            InputStream is = new FileInputStream(new File(outPath));
            XWPFDocument doc = new XWPFDocument(is);
            XWPFTable sourceTable = doc.getTableArray(2);
            int height = 0;
            int width1 = 0;
            int width2 = 0;
            int width3 = 0;
            int width4 = 0;
            String[] desName = {
                    "子MB名称",
                    "子MB类型",
                    "经度",
                    "纬度",
                    "大地高",
                    "海拔高",
                    "点位误差",
                    "纬度误差",
                    "经度误差",
                    "大地高误差",
                    "海拔误差",
                    "原图误差",
                    "面积",
                    "结构",
                    "子MB形状",
                    "圆内半径",
                    "圆外半径",
                    "矩形长",
                    "矩形宽",
                    "矩形长方向夹角"
            };
            String[] unitName = {
                    "-",
                    "-",
                    "dms",
                    "dms",
                    "m",
                    "m",
                    "m",
                    "s",
                    "s",
                    "m",
                    "m",
                    "m",
                    "m2",
                    "-",
                    "-",
                    "m",
                    "m",
                    "m",
                    "m",
                    "dms"
            };
            for (int i = 0; i < subTables.size(); i++) {
                RepacigiSubTable sub = subTables.get(i);
                if (i == 0) {
                    XWPFTableRow firstRow = sourceTable.getRow(0);
                    height = firstRow.getHeight();
                    width1 = firstRow.getCell(0).getWidth();
                    width2 = firstRow.getCell(1).getWidth();
                    width3 = firstRow.getCell(2).getWidth();
                    width4 = firstRow.getCell(3).getWidth();
                    //
                    for (int j = 0; j < 20; j++) {
                        XWPFTableRow row = sourceTable.getRow(j);
                        XWPFTableCell cell = row.getCell(3);
                        getCell(cell, j, sub);
                    }
                } else {
                    for (int j = 0; j < 20; j++) {
                        XWPFTableRow row = sourceTable.createRow();
                        row.setHeight(height);
                        XWPFTableCell cell = row.getCell(0);
                        cell.setWidth(width1 + "");
                        cell.setText((j + 1) + "");

                        cell = row.getCell(1);
                        cell.setWidth(width2 + "");
                        cell.setText(desName[j]);

                        cell = row.getCell(2);
                        cell.setWidth(width3 + "");
                        cell.setText(unitName[j]);

                        cell = row.getCell(3);
                        cell.setWidth(width4 + "");
                        getCell(cell, j, sub);

                    }
                }
            }
            OutputStream os = Files.newOutputStream(Paths.get(outPath));
            doc.write(os);
            os.close();
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void getCell(XWPFTableCell cell, int j, RepacigiSubTable sub) {
        switch (j) {
            case 0:
                cell.setText(sub.getSubName());
                break;
            case 1:
                String type = "";
                if (StringUtils.isNotBlank(sub.getSubType())) {
                    TargetSubType subType = targetSubTypeService.lambdaQuery().eq(TargetSubType::getTypeId, sub.getSubType()).one();
                    if (ObjectUtil.isNotEmpty(subType)) {
                        type = subType.getTypeName();
                    }
                }
                cell.setText(type);
                break;
            case 2:
                cell.setText(sub.getLon());
                break;
            case 3:
                cell.setText(sub.getLat());
                break;
            case 4:
                cell.setText(sub.getGeoHeight());
                break;
            case 5:
                cell.setText(sub.getAltitude());
                break;
            case 6:
                cell.setText(sub.getPlotError());
                break;
            case 7:
                cell.setText(sub.getLatError());
                break;
            case 8:
                cell.setText(sub.getLonError());
                break;
            case 9:
                cell.setText(sub.getGeoHeightError());
                break;
            case 10:
                cell.setText(sub.getAltitudeError());
                break;
            case 11:
                cell.setText(sub.getMasterMapError());
                break;
            case 12:
                cell.setText(sub.getArea());
                break;
            case 13:
                cell.setText(sub.getStructureType());
                break;
            case 14:
                cell.setText(sub.getShapeType());
                break;
            case 15:
                cell.setText(sub.getInRadius());
                break;
            case 16:
                cell.setText(sub.getOutRadius());
                break;
            case 17:
                cell.setText(sub.getLength());
                break;
            case 18:
                cell.setText(sub.getWide());
                break;
            case 19:
                cell.setText(sub.getAzimuthAngle());
                break;
            default:
                break;
        }
    }

    @Override
    public Result exportSubject(JSONObject jsonObject, HttpServletRequest request) {
        //标识
        String tarId = jsonObject.getString("tarId");
        String imageData = jsonObject.getString("imageData");
        String userId = redisUseService.getUserId(request.getHeader("Id"));
        RepacigiMainTable repacigiMainTable = repacigiMainTableService.lambdaQuery()
                .eq(RepacigiMainTable::getTarId, tarId)
                .one();
        if (ObjectUtil.isEmpty(repacigiMainTable)) {
            return ResultUtil.error(500, "MB数据不存在，请选择MB");
        }
        try {
            FileUtil.mkdir(keyWordSystem.getFILE_URL() + "/file/special");
            String time = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
            boolean image = MyUtil.base64ToImage(imageData, keyWordSystem.getFILE_URL() + "/file/special/" + time + ".png");
            if (!image) {
                return ResultUtil.error(500, "图片获取异常，请重试");
            }
            ImageSpecialSubject imageSpecialSubject = imageSpecialSubjectService.lambdaQuery().eq(ImageSpecialSubject::getRelId, userId).one();
            if (ObjectUtil.isNull(imageSpecialSubject)) {
                return ResultUtil.error(500, "专题创建异常，请重试");
            }
            String docType = "";
            if (StringUtils.isBlank(imageSpecialSubject.getPlateType())) {
                docType = "横版";
            }
            String srcPath = "/成果导入横版模板.docx";
            if ("竖版".equals(imageSpecialSubject.getPlateType())) {
                srcPath = "/成果导入竖版模板.docx";
            }
            InputStream ins = this.getClass().getResourceAsStream(srcPath);

//            srcPath = "D:/data/newTarget/成果导入横版模板.docx";
//            InputStream ins = new FileInputStream(srcPath);
            if (null == ins) {
                return ResultUtil.error(500, "模板异常，请重试");
            }
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins, TemplateEngineKind.Freemarker);
            FieldsMetadata fieldsMetadata = report.createFieldsMetadata();
            IContext context = report.createContext();
            // 创建要替换的文本变量
            context.put("specialName", StringUtils.isBlank(imageSpecialSubject.getSpecialName()) ? "" : imageSpecialSubject.getSpecialName());
            context.put("overview", StringUtils.isBlank(imageSpecialSubject.getOverview()) ? "" : imageSpecialSubject.getOverview());
            //表格内容
            context.put("country", StringUtils.isBlank(repacigiMainTable.getCountry()) ? "" : repacigiMainTable.getCountry());
            context.put("tarRegion", StringUtils.isBlank(repacigiMainTable.getTarRegion()) ? "" : repacigiMainTable.getTarRegion());
            context.put("tarName", StringUtils.isBlank(repacigiMainTable.getTarName()) ? "" : repacigiMainTable.getTarName());
            context.put("tarSerial", StringUtils.isBlank(repacigiMainTable.getTarSerial()) ? "" : repacigiMainTable.getTarSerial());
            context.put("tarGradient", StringUtils.isBlank(repacigiMainTable.getTarGradient()) ? "" : repacigiMainTable.getTarGradient());
            String tarType = "";
            RepacigiBaseTable repacigiBaseTable = repacigiBaseTableService.getById(repacigiMainTable.getTarType());
            if (ObjectUtil.isNotNull(repacigiBaseTable)) {
                tarType = repacigiBaseTable.getTypeName();
            }
            context.put("tarType", tarType);
            context.put("subPosition", StringUtils.isBlank(repacigiMainTable.getSubPosition()) ? "" : repacigiMainTable.getSubPosition());
            context.put("coordinateSystem", StringUtils.isBlank(repacigiMainTable.getCoordinateSystem()) ? "" : repacigiMainTable.getCoordinateSystem());
            context.put("lon", StringUtils.isBlank(repacigiMainTable.getLon()) ? "" : repacigiMainTable.getLon());
            context.put("lat", StringUtils.isBlank(repacigiMainTable.getLat()) ? "" : repacigiMainTable.getLat());
            context.put("geoHeight", StringUtils.isBlank(repacigiMainTable.getGeoHeight()) ? "" : repacigiMainTable.getGeoHeight());
            context.put("altitude", StringUtils.isBlank(repacigiMainTable.getAltitude()) ? "" : repacigiMainTable.getAltitude());
            context.put("reorganizeDate", StringUtils.isBlank(repacigiMainTable.getReorganizeDate()) ? "" : repacigiMainTable.getReorganizeDate());
            context.put("reorganizeUnit", StringUtils.isBlank(repacigiMainTable.getReorganizeUnit()) ? "" : repacigiMainTable.getReorganizeUnit());
            //图片处理
            fieldsMetadata.addFieldAsImage("imageData");
            IImageProvider imageProvider = new FileImageProvider(new File(keyWordSystem.getFILE_URL() + "/file/special/" + time + ".png"));
            context.put("imageData", imageProvider);
            report.setFieldsMetadata(fieldsMetadata);
            //子目标处理
            sub(tarId, context, fieldsMetadata);
//            List<RepacigiSubTable> repacigiSubTables = repacigiSubTableService
//                    .lambdaQuery()
//                    .eq(RepacigiSubTable::getTargetId, tarId)
//                    .list();
//            context.put("item", repacigiSubTables);
//            FieldsMetadata fm = report.createFieldsMetadata();
//            fm.load("item", RepacigiSubTable.class, true);
            // 输出到本地目录
            String fileName = imageSpecialSubject.getSpecialName() + "_成果报告_" + time;
            String storePath = fileUploadDir + "/file/special/" + fileName + ".docx";
            File file = new File(storePath);
            FileOutputStream out = new FileOutputStream(file);
            report.process(context, out);
//            if (CollectionUtil.isNotEmpty(repacigiSubTables)) {
//                getSubTable(storePath, repacigiSubTables);
//            }
            //复制表格
//            WordUtils.copyTableByLoop2(storePath, 2, repacigiSubTables.size() - 1, storePath);
            //表格赋值
//            WordUtils.setTableValue(storePath, repacigiSubTables);
            FileTable fileTable = new FileTable();
            fileTable.setRelId(userId);
            fileTable.setName(FileUtil.getName(fileName));
            fileTable.setFileSize(String.valueOf(file.length()));
            fileTable.setType("2");
            fileTable.setFileUrl(file.getAbsolutePath());
            fileTable.setCreatePersion(userId);
            fileTable.setCreateTime(LocalDateTime.now());
            fileTable.setUpdateTime(LocalDateTime.now());
            // todo:添加人
            fileTableService.save(fileTable);
            JSONObject json = new JSONObject();
            json.put("fileUrl", keyWordSystem.getSERVER_URL() + "/file/special/" + fileName + ".docx");
            json.put("fileName", fileName + ".docx");
            return ResultUtil.success(json);
        } catch (Exception e) {
            log.error("导出专题异常:{}", e.getMessage(), e);
            return ResultUtil.error(500, "导出专题异常");
        }
    }

    private void sub(String tarId, IContext context, FieldsMetadata fieldsMetadata) {
        // 查询子目标
        List<RepacigiSubTable> repacigiSubTables = repacigiSubTableService
                .lambdaQuery()
                .eq(RepacigiSubTable::getTargetId, tarId)
                .list();
        try {
            List<SubjectSubVo> subVos = new LinkedList<>();
            //表头
            SubjectSubVo head = new SubjectSubVo();
            head.setTotal("序号");
            head.setName("说明");
            head.setUnit("单位");
            head.setMessage("内容");
            subVos.add(head);
            String[] totals = {
                    "子MB名称",
                    "子MB类型",
                    "经度",
                    "纬度",
                    "大地高",
                    "海拔高",
                    "点位误差",
                    "纬度误差",
                    "经度误差",
                    "大地高误差",
                    "海拔误差",
                    "原图误差",
                    "面积",
                    "结构",
                    "子MB形状",
                    "圆内半径",
                    "圆外半径",
                    "矩形长",
                    "矩形宽",
                    "矩形长方向夹角"
            };
            String[] units = {
                    "-",
                    "-",
                    "dms",
                    "dms",
                    "m",
                    "m",
                    "m",
                    "s",
                    "s",
                    "m",
                    "m",
                    "m",
                    "m2",
                    "-",
                    "-",
                    "m",
                    "m",
                    "m",
                    "m",
                    "dms"
            };
            if (CollectionUtil.isNotEmpty(repacigiSubTables)) {
                for (RepacigiSubTable subTable : repacigiSubTables) {
                    for (int j = 0; j < totals.length; j++) {
                        SubjectSubVo vo = new SubjectSubVo();
                        vo.setTotal((j + 1) + "");
                        vo.setName(totals[j]);
                        vo.setUnit(units[j]);
                        switch (j) {
                            case 0:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getSubName()));
                                break;
                            case 1:
                                String typeName = "";
                                RepacigiBaseTable table = repacigiBaseTableService.getById(subTable.getSubType());
                                if (ObjectUtil.isNotEmpty(table)) {
                                    typeName = table.getTypeName();
                                }
                                vo.setMessage(typeName);
                                break;
                            case 2:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getLon()));
                                break;
                            case 3:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getLat()));
                                break;
                            case 4:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getGeoHeight()));
                                break;
                            case 5:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getAltitude()));
                                break;
                            case 6:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getPointError()));
                                break;
                            case 7:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getLatError()));
                                break;
                            case 8:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getLonError()));
                                break;
                            case 9:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getGeoHeightError()));
                                break;
                            case 10:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getAltitudeError()));
                                break;
                            case 11:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getMasterMapError()));
                                break;
                            case 12:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getArea()));
                                break;
                            case 13:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getStructureType()));
                                break;
                            case 14:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getShapeType()));
                                break;
                            case 15:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getInRadius()));
                                break;
                            case 16:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getOutRadius()));
                                break;
                            case 17:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getLength()));
                                break;
                            case 18:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getWide()));
                                break;
                            case 19:
                                vo.setMessage(FileElseUtil.getObjectToString(subTable.getAzimuthAngle()));
                                break;
                            default:
                                vo.setMessage("");
                                break;
                        }
                        subVos.add(vo);
                    }
                }
            }
            context.put("item", subVos);
            fieldsMetadata.load("item", SubjectSubVo.class, true);
        } catch (Exception e) {
            log.error("子目标处理异常：{}", e.getMessage(), e);
        }
    }

}
